package com.mxf.example.security;

import com.mxf.example.exception.BizException;
import com.mxf.example.utils.tools.CollectionTools;
import com.mxf.example.utils.tools.PathMatcherUtil;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;


@Component
public class JwtAuthorizationTokenFilter extends OncePerRequestFilter {

    private final UserDetailsService userDetailsService;
    private final JwtTokenUtil jwtTokenUtil;
    private final String tokenHeader;

    @Value("${url.pass}")
    String passurl;

    public JwtAuthorizationTokenFilter(@Qualifier("jwtUserDetailsService") UserDetailsService userDetailsService,
                                       JwtTokenUtil jwtTokenUtil, @Value("${config.jwt.token}") String tokenHeader) {
        this.userDetailsService = userDetailsService;
        this.jwtTokenUtil = jwtTokenUtil;
        this.tokenHeader = tokenHeader;
    }

    //doFilterInternal() 这个方法就是这个过滤器的精髓了。首先从header中获取凭证authToken，从中挖掘出来我们的username，然后看看上下文中是否有我们以这个username为标识的主体。
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        final String requestHeader = request.getHeader(this.tokenHeader);
        String uri = request.getRequestURI();
        String[] passurls = passurl.split(",");
        if (PathMatcherUtil.matches(Arrays.asList(passurls), uri)) {
            chain.doFilter(request, response);
        } else {
            if (requestHeader != null) {
                String username = "";
                try {
                    username = jwtTokenUtil.getUsernameFromToken(requestHeader);
                } catch (Exception e) {
                    request.setAttribute("filter.error", new BizException("token失效"));
                    request.getRequestDispatcher("/error/exthrow").forward(request, response);
                    return;
                }
                UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
                if (jwtTokenUtil.validateToken(requestHeader, userDetails)) {
                    UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                    SecurityContextHolder.getContext().setAuthentication(authentication);
                } else {
                    // 将filter中的异常捕获，发送到error controller，交给全局异常处理器处理（springboot全局异常处理不能直接拦截filter中的异常，需要转发处理）
                    request.setAttribute("filter.error", new BizException("token失效"));
                    //将异常分发到/error/exthrow控制器
                    request.getRequestDispatcher("/error/exthrow").forward(request, response);
                    return;
                }
            } else {
                request.setAttribute("filter.error", new BizException("token为空"));
                request.getRequestDispatcher("/error/exthrow").forward(request, response);
                return;
            }
            chain.doFilter(request, response);
        }
    }
}

